using System.Drawing;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using _3Dto2D.Configuration;
using _3Dto2D.Interfaces;
using _3Dto2D.Services;
using _3Dto2D.ViewModels;

using OpenTK.GLControl;
using OpenTK.Windowing.Common;




namespace _3Dto2D;

public partial class Main : Form
{

    private readonly MainViewModel _viewModel;
    private readonly IRenderEngine _renderEngine;
    private readonly ILogger<Main> _logger;
    private readonly RenderSettings _settings;

    // UI Controls
    private GLControl _renderPanel = null!;
    private NumericUpDown _frameSelector = null!;
    private Button _btnImportMesh = null!;
    private Button _btnImportLib = null!;
    private Button _btnImportHands = null!;
    private Button _btnExport = null!;
    private Button _btnColorPicker = null!;
    private CheckBox _chkShowHands = null!;
    private CheckBox _chkBlankHands = null!;
    private Label _lblStatus = null!;
    private ProgressBar _progressBar = null!;
    private GroupBox _grpRotation = null!;
    private GroupBox _grpMove = null!;
    private NumericUpDown _nudRotX = null!, _nudRotY = null!, _nudRotZ = null!;
    private NumericUpDown _nudMoveX = null!, _nudMoveY = null!;

    // Labels for file names
    private Label _lblCharacterFile = null!;
    private Label _lblMeshFile = null!;
    private Label _lblHandRefFile = null!;

    // Other controls
    private Button _btnSaveRef = null!;
    private TextBox _txtOffsetX = null!;
    private TextBox _txtOffsetY = null!;
    private FlowLayoutPanel _flowLayoutPanel = null!;



    public Main(IServiceProvider serviceProvider)
    {

        _viewModel = serviceProvider.GetRequiredService<MainViewModel>();
        _renderEngine = serviceProvider.GetRequiredService<IRenderEngine>();
        _logger = serviceProvider.GetRequiredService<ILogger<Main>>();
        _settings = serviceProvider.GetRequiredService<RenderSettings>();

        InitializeModernComponent();
        SetupModernUI();
        BindEvents();

        _logger.LogInformation("Modern main form created");
    }

    private void InitializeModernComponent()
    {
        SuspendLayout();

        // Form properties
        Text = "3D Model to 2D Animation";
        Size = new Size(800, 600);
        StartPosition = FormStartPosition.CenterScreen;
        MinimumSize = new Size(600, 400);

        ResumeLayout(false);
    }

    private void SetupModernUI()
    {
        // Create render panel
        _renderPanel = new GLControl
        {
            Name = "RenderPanel",
            Size = new Size(_settings.OutputWidth, _settings.OutputHeight),
            Location = new Point(20, 20),
            BackColor = _settings.BackgroundColor,
            Profile = ContextProfile.Core,
            APIVersion = new Version(3, 3),

        };
        Controls.Add(_renderPanel);

        // Frame selector
        _frameSelector = new NumericUpDown
        {
            Location = new Point(20, _renderPanel.Bottom + 10),
            Size = new Size(100, 23),
            Minimum = 0,
            Maximum = 0
        };
        Controls.Add(_frameSelector);

        var lblFrame = new Label
        {
            Text = "Frame:",
            Location = new Point(_frameSelector.Right + 5, _frameSelector.Top + 3),
            Size = new Size(50, 20)
        };
        Controls.Add(lblFrame);

        // --- Control Layout Panel ---
        _flowLayoutPanel = new FlowLayoutPanel
        {
            FlowDirection = FlowDirection.LeftToRight,
            Location = new Point(20, _frameSelector.Bottom + 10),
            Size = new Size(450, 200), // Adjust size as needed
            WrapContents = true
        };
        Controls.Add(_flowLayoutPanel);

        // Add controls to the FlowLayoutPanel
        _btnImportLib = CreateButton("Character", Point.Empty); _flowLayoutPanel.Controls.Add(_btnImportLib);
        _lblCharacterFile = new Label { Text = "No file loaded", AutoSize = true, Margin = new Padding(5, 5, 15, 5) }; _flowLayoutPanel.Controls.Add(_lblCharacterFile);

        _btnImportMesh = CreateButton("3D Mesh", Point.Empty); _flowLayoutPanel.Controls.Add(_btnImportMesh);
        _lblMeshFile = new Label { Text = "No mesh loaded", AutoSize = true, Margin = new Padding(5, 5, 15, 5) }; _flowLayoutPanel.Controls.Add(_lblMeshFile);

        _btnImportHands = CreateButton("Hand Ref", Point.Empty); _flowLayoutPanel.Controls.Add(_btnImportHands);
        _lblHandRefFile = new Label { Text = "No file loaded", AutoSize = true, Margin = new Padding(5, 5, 15, 5) }; _flowLayoutPanel.Controls.Add(_lblHandRefFile);

        // Force a new line
        _flowLayoutPanel.SetFlowBreak(_lblHandRefFile, true);

        _btnExport = CreateButton("Create Lib", Point.Empty); _flowLayoutPanel.Controls.Add(_btnExport);
        _btnSaveRef = CreateButton("SaveRef", Point.Empty); _flowLayoutPanel.Controls.Add(_btnSaveRef);
        _btnColorPicker = CreateButton("Bk", Point.Empty); _flowLayoutPanel.Controls.Add(_btnColorPicker);

        _flowLayoutPanel.SetFlowBreak(_btnColorPicker, true);

        _chkShowHands = CreateCheckBox("Show Hands", Point.Empty, false); _flowLayoutPanel.Controls.Add(_chkShowHands);
        _chkBlankHands = CreateCheckBox("Blank Hands", Point.Empty, false); _flowLayoutPanel.Controls.Add(_chkBlankHands);

        _txtOffsetX = new TextBox { Size = new Size(50, 20), Margin = new Padding(5) }; _flowLayoutPanel.Controls.Add(_txtOffsetX);
        _txtOffsetY = new TextBox { Size = new Size(50, 20), Margin = new Padding(5) }; _flowLayoutPanel.Controls.Add(_txtOffsetY);

        // Transform controls
        _grpRotation = new GroupBox
        {
            Text = "Rotation",
            Location = new Point(_renderPanel.Right + 20, 20),
            Size = new Size(200, 120)
        };
        Controls.Add(_grpRotation);

        _grpMove = new GroupBox
        {
            Text = "Move",
            Location = new Point(_renderPanel.Right + 20, _grpRotation.Bottom + 10),
            Size = new Size(200, 90)
        };
        Controls.Add(_grpMove);

        CreateTransformControls();

        // Status and progress
        _lblStatus = new Label
        {
            Text = "Ready",
            Location = new Point(20, Height - 60),
            Size = new Size(400, 20),
            Anchor = AnchorStyles.Bottom | AnchorStyles.Left
        };
        Controls.Add(_lblStatus);

        _progressBar = new ProgressBar
        {
            Location = new Point(20, Height - 35),
            Size = new Size(400, 20),
            Anchor = AnchorStyles.Bottom | AnchorStyles.Left,
            Visible = false
        };
        Controls.Add(_progressBar);
    }

    private Button CreateButton(string text, Point location)
    {
        var button = new Button
        {
            Text = text,
            Location = location,
            Size = new Size(90, 25),
            UseVisualStyleBackColor = true
        };
        return button;
    }

    private CheckBox CreateCheckBox(string text, Point location, bool isChecked)
    {
        var checkBox = new CheckBox
        {
            Text = text,
            Location = location,
            Size = new Size(100, 20),
            Checked = isChecked,
            UseVisualStyleBackColor = true
        };
        return checkBox;
    }

    private void CreateTransformControls()
    {
        var y = 25;
        var spacing = 30;

        // Rotation controls
        CreateTransformControl("rotx", ref _nudRotX, new Point(10, y), _grpRotation);
        y += spacing;
        CreateTransformControl("roty", ref _nudRotY, new Point(10, y), _grpRotation);
        y += spacing;
        CreateTransformControl("rotz", ref _nudRotZ, new Point(10, y), _grpRotation);

        // Movement controls
        y = 25; // Reset y for the new group box
        CreateTransformControl("x", ref _nudMoveX, new Point(10, y), _grpMove);
        y += spacing;
        CreateTransformControl("y", ref _nudMoveY, new Point(10, y), _grpMove);
    }

    private void CreateTransformControl(string labelText, ref NumericUpDown control, Point location, GroupBox parent)
    {
        var label = new Label
        {
            Text = labelText,
            Location = location,
            Size = new Size(50, 20)
        };
        parent.Controls.Add(label);

        control = new NumericUpDown
        {
            Location = new Point(location.X + 55, location.Y - 2),
            Size = new Size(80, 23),
            Minimum = -360,
            Maximum = 360,
            DecimalPlaces = 2
        };
        parent.Controls.Add(control);
    }

    private void BindEvents()
    {
        // Button events
        _btnImportMesh.Click += Btn_ImportMesh_Click;
        _btnImportLib.Click += Btn_ImportLib_Click_Modern;
        _btnImportHands.Click += Btn_ImportHands_Click;
        _btnExport.Click += Btn_Export_Click;
        _btnColorPicker.Click += Btn_ColorPicker_Click;

        // Control events
        _frameSelector.ValueChanged += FrameSelector_ValueChanged;
        _chkShowHands.CheckedChanged += ChkShowHands_CheckedChanged;
        _chkBlankHands.CheckedChanged += ChkBlankHands_CheckedChanged;

        // Transform events
        _nudRotX.ValueChanged += Transform_ValueChanged;
        _nudRotY.ValueChanged += Transform_ValueChanged;
        _nudRotZ.ValueChanged += Transform_ValueChanged;
        _nudMoveX.ValueChanged += Transform_ValueChanged;
        _nudMoveY.ValueChanged += Transform_ValueChanged;

        // Render panel events
        _renderPanel.Paint += RenderPanel_Paint;
        _renderPanel.Load += RenderPanel_Load;

        // ViewModel events
        _viewModel.PropertyChanged += OnViewModelPropertyChanged;

        // Form events
        Load += Main_Load;

        _btnSaveRef.Click += Btn_SaveRef_Click_Modern;

    }

    private void Main_Load(object? sender, EventArgs e)
    {
        try
        {
            _logger.LogInformation("Loading modern main form");

            // Render engine is now initialized in _renderPanel_Load

            // Load default library if exists
            var defaultLibPath = Path.Combine(_settings.DefaultDataPath, "_Mir2_CArmour.Lib");
            if (File.Exists(defaultLibPath))
            {
                // This is not ideal, but for now we'll block on the async method.
                _viewModel.LoadLibraryAsync(defaultLibPath, true).Wait();
            }


            UpdateUI();

            _logger.LogInformation("Modern main form loaded successfully");
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "Failed to load modern main form");
            MessageBox.Show($"Initialization failed: {ex.Message}", "Error",
                MessageBoxButtons.OK, MessageBoxIcon.Error);
        }
    }


    private void RenderPanel_Paint(object? sender, PaintEventArgs e)
    {
        _renderEngine.RenderFrame(_viewModel.CurrentFrameData);
        _renderPanel.SwapBuffers();
    }

    private void RenderPanel_Load(object? sender, EventArgs e)
    {
        // The GLControl's context is now current. Bindings are loaded automatically.
        _renderPanel.MakeCurrent();

        // Initialize the render engine, which will now use OpenTK's static GL class
        _renderEngine.Initialize();
    }








    #region Event Handlers

    private void Btn_ImportMesh_Click(object? sender, EventArgs e)
    {
        using var openFileDialog = new OpenFileDialog
        {
            InitialDirectory = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Mesh"),
            Filter = "3D Model Files (*.x)|*.x|All Files (*.*)|*.*",
            Title = "Select 3D Mesh File"
        };

        if (openFileDialog.ShowDialog() == DialogResult.OK)
        {
            _viewModel.LoadMesh(openFileDialog.FileName);
        }
    }

    private async void Btn_ImportLib_Click_Modern(object? sender, EventArgs e)
    {
        using var openFileDialog = new OpenFileDialog
        {
            InitialDirectory = _settings.DefaultDataPath,
            Filter = "Library Files (*.lib)|*.lib|All Files (*.*)|*.*",
            Title = "Select Reference Library File"
        };

        if (openFileDialog.ShowDialog() == DialogResult.OK)
        {
            await _viewModel.LoadLibraryAsync(openFileDialog.FileName, true);
        }
    }

    private async void Btn_ImportHands_Click(object? sender, EventArgs e)
    {
        using var openFileDialog = new OpenFileDialog
        {
            InitialDirectory = Path.Combine(_settings.DefaultDataPath, "Hands"),
            Filter = "Library Files (*.lib)|*.lib|All Files (*.*)|*.*",
            Title = "Select Hand Library File"
        };

        if (openFileDialog.ShowDialog() == DialogResult.OK)
        {
            await _viewModel.LoadHandLibraryAsync(openFileDialog.FileName);
        }
    }

    private async void Btn_Export_Click(object? sender, EventArgs e)
    {
        using var saveFileDialog = new SaveFileDialog
        {
            InitialDirectory = _settings.DefaultOutputPath,
            Filter = "Library Files (*.lib)|*.lib|All Files (*.*)|*.*",
            DefaultExt = "lib",
            Title = "Export Library As..."
        };

        if (saveFileDialog.ShowDialog() == DialogResult.OK)
        {
            await _viewModel.ExportLibraryAsync(saveFileDialog.FileName);
        }
    }

    private void Btn_ColorPicker_Click(object? sender, EventArgs e)
    {
        using var colorDialog = new ColorDialog();
        if (colorDialog.ShowDialog() == DialogResult.OK)
        {
            _settings.BackgroundColor = colorDialog.Color;
            _renderEngine.SetBackgroundColor(colorDialog.Color);
            _renderPanel.BackColor = colorDialog.Color;
        }
    }

    private void FrameSelector_ValueChanged(object? sender, EventArgs e)
    {
        _viewModel.CurrentFrame = (int)_frameSelector.Value;
        UpdateTransformControls();
        _renderPanel.Invalidate();
    }

    private async void Btn_SaveRef_Click_Modern(object? sender, EventArgs e)
    {
        if (_viewModel.CurrentLibrary == null) return;

        using var saveFileDialog = new SaveFileDialog
        {
            InitialDirectory = _settings.DefaultDataPath,
            Filter = "Library Files (*.lib)|*.lib|All Files (*.*)|*.*",
            DefaultExt = "lib",
            Title = "Save Reference Library"
        };

        if (saveFileDialog.ShowDialog() == DialogResult.OK)
        {
            await _viewModel.SaveLibraryAsync(saveFileDialog.FileName, true);
        }
    }

    private void ChkShowHands_CheckedChanged(object? sender, EventArgs e)
    {
        _viewModel.ShowHandImage = _chkShowHands.Checked;
        _renderPanel.Invalidate();
    }

    private void ChkBlankHands_CheckedChanged(object? sender, EventArgs e)
    {
        _viewModel.BlankHandImage = _chkBlankHands.Checked;
        _renderPanel.Invalidate();
    }

    private void Transform_ValueChanged(object? sender, EventArgs e)
    {
        if (_viewModel.CurrentFrameData?.Transform != null)
        {
            _viewModel.CurrentFrameData.Transform.RotationX = (float)_nudRotX.Value;
            _viewModel.CurrentFrameData.Transform.RotationY = (float)_nudRotY.Value;
            _viewModel.CurrentFrameData.Transform.RotationZ = (float)_nudRotZ.Value;
            _viewModel.CurrentFrameData.Transform.MoveX = (float)_nudMoveX.Value;
            _viewModel.CurrentFrameData.Transform.MoveY = (float)_nudMoveY.Value;
            _renderPanel.Invalidate();
        }
    }





    private void OnViewModelPropertyChanged(object? sender, System.ComponentModel.PropertyChangedEventArgs e)
    {
        if (InvokeRequired)
        {
            Invoke(() => OnViewModelPropertyChanged(sender, e));
            return;
        }

        switch (e.PropertyName)
        {
            case nameof(MainViewModel.StatusMessage):
                _lblStatus.Text = _viewModel.StatusMessage;
                break;
            case nameof(MainViewModel.IsExporting):
                UpdateExportingState();
                break;
            case nameof(MainViewModel.FrameCount):
                UpdateFrameSelector();
                break;
            case nameof(MainViewModel.CurrentFrameData):
                UpdateTransformControls();
                break;
            case nameof(MainViewModel.CurrentLibrary):
                _lblCharacterFile.Text = Path.GetFileName(_viewModel.CurrentLibrary?.FilePath ?? "No file loaded");
                break;
            case nameof(MainViewModel.CurrentMesh):
                _lblMeshFile.Text = Path.GetFileName(_viewModel.CurrentMesh?.FilePath ?? "No mesh loaded");
                break;
            case nameof(MainViewModel.HandLibrary):
                _lblHandRefFile.Text = Path.GetFileName(_viewModel.HandLibrary?.FilePath ?? "No file loaded");
                break;
        }
    }

    #endregion

    #region UI Updates

    private void UpdateUI()
    {
        UpdateFrameSelector();
        UpdateTransformControls();
        UpdateExportingState();
    }

    private void UpdateFrameSelector()
    {
        _frameSelector.Maximum = Math.Max(0, _viewModel.FrameCount - 1);
        _frameSelector.Enabled = _viewModel.HasLibrary;
    }

    private void UpdateTransformControls()
    {
        if (_viewModel.CurrentFrameData?.Transform != null)
        {
            var transform = _viewModel.CurrentFrameData.Transform;
            _nudRotX.Value = (decimal)transform.RotationX;
            _nudRotY.Value = (decimal)transform.RotationY;
            _nudRotZ.Value = (decimal)transform.RotationZ;
            _nudMoveX.Value = (decimal)transform.MoveX;
            _nudMoveY.Value = (decimal)transform.MoveY;

            _txtOffsetX.Text = _viewModel.CurrentFrameData.OffsetX.ToString();
            _txtOffsetY.Text = _viewModel.CurrentFrameData.OffsetY.ToString();
        }

        _grpRotation.Enabled = _viewModel.HasLibrary;
        _grpMove.Enabled = _viewModel.HasLibrary;
    }

    private void UpdateExportingState()
    {
        var isExporting = _viewModel.IsExporting;

        _btnImportMesh.Enabled = !isExporting;
        _btnImportLib.Enabled = !isExporting;
        _btnImportHands.Enabled = !isExporting;
        _btnExport.Enabled = !isExporting && _viewModel.HasLibrary;

        _progressBar.Visible = isExporting;

        if (isExporting)
        {
            _progressBar.Style = ProgressBarStyle.Marquee;
        }
        else
        {
            _progressBar.Style = ProgressBarStyle.Blocks;
            _progressBar.Value = 0;
        }
    }

    #endregion


}
